package com.leyou.user.service;

import com.leyou.common.enums.ExceptionEnum;
import com.leyou.common.exception.LyException;
import com.leyou.common.utils.BeanHelper;
import com.leyou.common.utils.NumberUtils;
import com.leyou.common.utils.constants.RegexPatterns;
import com.leyou.user.dto.UserDTO;
import com.leyou.user.entity.User;
import com.leyou.user.mapper.UserMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.amqp.AmqpException;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.awt.peer.CanvasPeer;
import java.security.Key;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import static com.leyou.common.constants.MQConstants.Exchange.SMS_EXCHANGE_NAME;
import static com.leyou.common.constants.MQConstants.RoutingKey.VERIFY_CODE_KEY;

@Service
@Slf4j
public class UserService {

    @Autowired
    private UserMapper userMapper;

    public Boolean validateData(String data, Integer type) {

        //data为空
        if (StringUtils.isBlank(data)) {
            log.error("【用户服务】校验数据为空，检查失败");
            throw new LyException(ExceptionEnum.REQUEST_PARAM_ERROR);
        }

        log.info("【用户服务】校验数据成功");


        User record = new User();
        switch (type) {
            case 1:
                record.setUsername(data);
                break;
            case 2:
                //TODO 如果是手机号则应该匹配一下手机号的格式
                record.setPhone(data);
                break;
            default:
                log.error("【用户服务】校验检查类型不存在，检查失败");
                throw new LyException(ExceptionEnum.REQUEST_PARAM_ERROR);
        }

        log.info("【用户服务】校验检查类型成功");

        //如果统计结果不等于1，则表示，没有查到，没有查到，则表示可用
        boolean result = false;
        try {
            result = this.userMapper.selectCount(record) != 1;
            log.info("【用户服务】数据唯一性检测成功");
        } catch (Exception e) {
            log.info("【用户服务】数据唯一性检测失败，数据库访问失败");
            throw new LyException(ExceptionEnum.DATA_SERVER_DEADE);
        }

        return result;
    }

    @Autowired
    private AmqpTemplate amqpTemplate;

    @Autowired
    private StringRedisTemplate redisTemplate;

    private final String KEY_PREFIX = "ly:user:verifyCode:";

    public void sendVerifyCode(String phone) {

        if (!phone.matches(RegexPatterns.PHONE_REGEX)) {
            throw new LyException(ExceptionEnum.REQUEST_PARAM_ERROR);
        }

        Map<String, String> msg = new HashMap<>();

        //生成验证码
        String code = NumberUtils.generateCode(5);

        msg.put("phone", phone);
        msg.put("code", code);

        try {
            amqpTemplate.convertAndSend(SMS_EXCHANGE_NAME, VERIFY_CODE_KEY, msg);
            log.info("【用户服务】xxxx");
        } catch (AmqpException e) {
            log.error("【用户服务】xxxx");
            throw new LyException(ExceptionEnum.MQ_CONN_ERROR);
        }

        try {
            redisTemplate.opsForValue().set(KEY_PREFIX + phone, code, 5, TimeUnit.MINUTES);
        } catch (Exception e) {

            throw new LyException(ExceptionEnum.REDIS_CONN_ERROR);
        }
    }

    @Autowired
    private BCryptPasswordEncoder passwordEncoder;

    @Transactional
    public void register(User user, String code) {

        String key = KEY_PREFIX + user.getPhone();
        //验证码，校验,验证码不存在，或者验证码验证失败
        if (!redisTemplate.hasKey(key) || !redisTemplate.opsForValue().get(key).equals(code)) {
            throw new LyException(ExceptionEnum.VERIFY_CODE_VALIDATE_FAIL);
        }
        //就应该立即马上，删除，redis中验证码，防止重复提交，验证，给redis减压，
        this.redisTemplate.delete(key);

        //对密码的明文进行加密，获取密文,每一次生成的盐值都不同，所以不能使用两次加密后比较密文进行加密
        String encodePass = passwordEncoder.encode(user.getPassword());
        user.setPassword(encodePass);

        //用户信息保存
        int count = this.userMapper.insertSelective(user);

        if (1 != count) {
            throw new LyException(ExceptionEnum.DATA_SAVE_ERROR);
        }
    }

    public UserDTO queryUserByNameAndPass(String username, String password) {

        User record = new User();
        record.setUsername(username);

        //根据用户名查询，要查也只有一个
        User user = this.userMapper.selectOne(record);

        //用户名不存在，或者密码不匹配
        if (null == user || !passwordEncoder.matches(password, user.getPassword())) {
            throw new LyException(ExceptionEnum.INVALID_NAME_PASS);
        }
        //返回封装时候，要把真正的值，不要把查询条件返回
        return BeanHelper.copyProperties(user,UserDTO.class);
    }
}
